package com.fmistuff.threadedcalc;
import java.math.BigInteger;

public class ExpressionNode 
{
	/*
	 * The expected length of the number in bits.
	 */
	protected double weight;
	
	/*
	 * The maximum number of threads that can compute this node.
	 */
	protected int maxthreads;
	protected BigInteger value;
	protected ExpressionOperands operand;
	protected ExpressionNode left;
	protected ExpressionNode right;
	
	public ExpressionNode(ExpressionNode left, ExpressionNode right, ExpressionOperands operand)
	{
		this.left = left;
		this.right = right;
		this.operand = operand;
		
		if (operand != null)
			weight = operand.GetWeight(left.weight, right.weight);
		
		maxthreads = 0;
		if (left != null)
			maxthreads += left.maxthreads;
		if (right != null)
			maxthreads += right.maxthreads;
		if (maxthreads == 0)
			maxthreads++;
	}
	
	public boolean IsSimple()
	{
		return false;
	}
	
	public BigInteger GetValue(ThreadPool pool, EvaluationThread thread) throws InterruptedException
	{
		if (!right.IsSimple())
			pool.evaluationQueue.add(right);
		
		BigInteger leftValue = left.GetValue(pool, thread);
		BigInteger rightValue = null;
		
		EvaluationThread rightThread = pool.evaluatedNodes.putIfAbsent(right, thread);
		
		if (rightThread != null)
		{
			rightThread.thread.join();
			rightValue = rightThread.result;
		}
		else
		{
			rightValue = right.GetValue(pool, thread);
		}
		
		value = operand.eval(leftValue, rightValue);
		return value;
	}
	
	public double GetWeight()
	{
		return weight;
	}
	
	public double GetNormalizedWeight(double totalWeight)
	{
		return weight / totalWeight;
	}
	
	public ExpressionNode GetLeftNode()
	{
		return left;
	}
	
	public ExpressionNode GetRightNode()
	{
		return right;
	}
	
	public ExpressionOperands GetOperand()
	{
		return operand;
	}
	
	public int GetMaxThreads()
	{
		return maxthreads;
	}
}